package org.tri.gui.worker;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import org.tri.persistence.PersistenceManager;

/**
 * La clase {@code PersistenceWorker} es un worker genérico que permite 
 * persistir cualquier entidad asociada a Hibernate en un thread distinto
 * del Swing.
 * @author kiira
 * @version 1.0, Feb 1, 2012
 */
public class PersistenceWorker extends SwingWorker {

    /** Objeto a guardar. */
    protected Object objectToSave;
    /** Lista de listeners. */
    private List<PersistenceListener> listenerList;
    /** Bandera para saber si evictear o no el objeto una vez guardado. */
    private boolean evictLater;

    /**
     * Inicializa el worker con el objeto a guardar.
     * @param toSave objeto a guardar.
     */
    public PersistenceWorker( Object toSave ) {
        objectToSave = toSave;

        listenerList = new ArrayList<PersistenceListener>();

    }//end constructor
    
    public PersistenceWorker( Object toSave, boolean evictLater ) {
        this( toSave );
        
        this.evictLater = evictLater;
        
    }

    /**
     * Agrega un listener de persistencia a la lista de listeners del worker.
     * @param listener listener a agregar.
     */
    public final void addPersistenceListener( PersistenceListener listener ) {
        listenerList.add( listener );

    }//end método addTableFillListener

    /**
     * Elimina un listener de la lista de listeners del worker.
     * @param listener listener a quitar.
     */
    public final void removePersistenceListener( PersistenceListener listener ) {
        listenerList.remove( listener );

    }//end método removeTableFillListener

    /**
     * Este método es llamado cuando el worker termina de realizar todas las
     * acciones necesarias de persistencia, informando a todos los listeners
     * de esto. Este método es llamado incluso si ocurre un error durante
     * la persistencia.
     */
    private void fireDonePersisting() {
        for ( final PersistenceListener listener : listenerList )
            SwingUtilities.invokeLater( new Runnable() {

                @Override
                public void run() {
                    listener.donePersisting();
                }

            } );

    }//end métdoo fireDoneFillingTable

    /**
     * Este método es llamado cuando ocurre un error durante la persistencia
     * del objeto, informando a todos los listeners de lo ocurrido.
     * @param ex excepción resultado del error.
     */
    private void fireErrorPersisting( final ExecutionException ex ) {
        for ( final PersistenceListener listener : listenerList )
            SwingUtilities.invokeLater( new Runnable() {

                @Override
                public void run() {
                    listener.errorPersisting( ex );
                }

            } );            

    }//end método errorFillingTable

    /**
     * {@inheritDoc} 
     */
    @Override
    protected Object doInBackground() throws Exception {
        //almacenamos el objeto en la base de datos
        PersistenceManager.makePersistent( objectToSave );
        
        if ( evictLater )
            PersistenceManager.evict( objectToSave );

        return null;

    }//end método doInBackground

    /**
     * Comprueba si ocurrieron errores en la persistencia y envia los eventos
     * a los listeners.
     */
    @Override
    protected void done() {
        super.done();
        
        try {
            //comprobamos que termino con exito
            get();

        } catch ( InterruptedException ex ) {
        } catch ( ExecutionException ex ) {
            fireErrorPersisting( ex );

        } finally {
            fireDonePersisting();

        }

    }//end método done
    
}//end clase PersistenceWorker
